package com.csw.android.ffmpegtest.camera

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.hardware.camera2.CameraCaptureSession
import android.hardware.camera2.CameraDevice
import android.hardware.camera2.CameraManager
import android.view.Surface
import androidx.core.app.ActivityCompat
import com.csw.android.dev_utils.handler.MainHandler
import com.csw.android.dev_utils.utils.LogUtils
import com.csw.android.ffmpegtest.app.MyApplication

class CameraController {
    val cameraManager =
        MyApplication.instance.getSystemService(Context.CAMERA_SERVICE) as CameraManager
    val mainHandler = MainHandler()
    private val idCameraConnectMap = HashMap<String, CameraConnect>()
    val callback = object : CameraDevice.StateCallback() {
        override fun onOpened(camera: CameraDevice) {
            ensureCameraConnect(camera.id).connect(camera)
        }

        override fun onDisconnected(camera: CameraDevice) {
            ensureCameraConnect(camera.id).disConnect(camera)
        }

        override fun onError(camera: CameraDevice, error: Int) {
            LogUtils.e(this@CameraController, "$error")
            ensureCameraConnect(camera.id).disConnect(camera)
        }
    }

    /**
     * 连接摄像头
     */
    fun connectToCamera(context: Context, cameraId: String) {
        if (ActivityCompat.checkSelfPermission(
                context,
                Manifest.permission.CAMERA
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            throw RuntimeException("未授予摄像头权限")
        }
        cameraManager.openCamera(cameraId, callback, mainHandler)
    }

    /**
     * 添加输出画面
     */
    fun addSurface(cameraId: String, surface: Surface) {
        ensureCameraConnect(cameraId).addSurface(surface)
    }

    private fun ensureCameraConnect(cameraId: String): CameraConnect {
        var conn = idCameraConnectMap[cameraId]
        if (conn == null) {
            conn = CameraConnect(cameraId)
            idCameraConnectMap[cameraId] = conn
        }
        return conn
    }

    fun release() {
        for (i in idCameraConnectMap) {
            i.value.release()
        }
    }

    private inner class CameraConnect(val cameraId: String) {
        private val surfaces = ArrayList<Surface>()
        private var mCamera: CameraDevice? = null
        private var currSession: CameraCaptureSession? = null
        fun addSurface(surface: Surface) {
            surfaces.add(surface)
        }

        fun connect(camera: CameraDevice) {
            mCamera = camera
            camera.createCaptureSession(surfaces, object : CameraCaptureSession.StateCallback() {
                override fun onConfigured(session: CameraCaptureSession) {
                    currSession = session
                    session.setRepeatingRequest(
                        camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW).apply {
                            for (surface in surfaces) {
                                addTarget(surface)
                            }
                        }.build(),
                        object : CameraCaptureSession.CaptureCallback() {
                        },
                        null
                    )
                }

                override fun onConfigureFailed(session: CameraCaptureSession) {
                    LogUtils.e(this@CameraController, "onConfigureFailed")
                    if (currSession == session) {
                        currSession = null
                    }
                }
            }, null)
        }

        fun disConnect(camera: CameraDevice) {
            if (mCamera == camera) {
                mCamera = null
            }
        }

        fun release() {
            currSession?.stopRepeating()
            currSession?.abortCaptures()
            mCamera?.close()
        }
    }

}